package org.monkeyk.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

/**
 * 2010-8-18
 * 
 * 对SWING的一些封装,具体有:<br>
 * <ul>
 * <li>根据界面大小计算左上角坐标值(保证界面位于屏幕最中间)</li>
 * <li>设置UI</li>
 * <li>更新UI</li>
 * <li>封装的JOptionPane</li>
 * </ul>
 * 
 * @author mkk(monkeyking1987@126.com)
 */
public class SwingUtil {

	// UI枚举类型
	public static enum UIType {

		WINDOWS, WINDOWS_CLASSIC, METAL, MOTIF
	};

	// toolkit
	private static Toolkit toolkit = Toolkit.getDefaultToolkit();

	/**
	 * 根据界面的长度与宽度确定界面的左上角坐标值<br>
	 * 保证界面位于屏幕最中间
	 * 
	 * @param width
	 *            界面长度
	 * @param height
	 *            界面宽度
	 * @return
	 */
	public static Point getStartPoint(int width, int height) {
		if (width < 0 || height < 0) {
			throw new IllegalArgumentException("width or height < 0");
		}
		Dimension dim = toolkit.getScreenSize();
		Point point = new Point();
		point.x = dim.width / 2 - width / 2;
		point.y = dim.height / 2 - height / 2;
		return point;
	}

	/**
	 * 设置UI,默认为windows外观<br>
	 * 说明:一般此方法在界面程序启动之前调用,如:<br>
	 * <code>
	 *    setUI(UIType.METAL);
	 *    new MainFrame().setVisiable(true);
     * </code> <b>注意: JDK版本1.6或以上</b>
	 * 
	 * @param type
	 *            外观枚举类型,若为NULL则外观为windows
	 * @return true或者false,表示UI设置是否成功
	 */
	public static boolean setUI(UIType type) {
		try {
			if (UIType.WINDOWS_CLASSIC.equals(type)) {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
			} else if (UIType.METAL.equals(type)) {
				UIManager
						.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
			} else if (UIType.MOTIF.equals(type)) {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
			} else {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			}
			JFrame.setDefaultLookAndFeelDecorated(true);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * 更新UI
	 * 
	 * @param c
	 *            需要更新的组件,若为NULL,则什么事也不做
	 * @param type
	 *            外观枚举类型,若为NULL则外观为windows
	 * @return true或者false,表示UI更新是否成功
	 */
	public static boolean updateUI(Component c, UIType type) {
		if (c == null) {
			return false;
		}
		try {
			if (UIType.WINDOWS_CLASSIC.equals(type)) {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
			} else if (UIType.METAL.equals(type)) {
				UIManager
						.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
			} else if (UIType.MOTIF.equals(type)) {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
			} else {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			}
			SwingUtilities.updateComponentTreeUI(c);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * 由ResultSet对象创建TableModel<br>
	 * 注意: 1.ResultSet必须支持可滚动 2.在方法内部创建TableModel可能会抛出SQLException
	 * 
	 * @param rs
	 *            ResultSet对象,若为NULL则抛出NullPointerException
	 * @throws SQLException
	 * @return
	 */
	public static TableModel createTableModelByResultset(final ResultSet rs)
			throws SQLException {
		if (rs == null) {
			throw new NullPointerException("rs is null");
		}
		final ResultSetMetaData rsmd = rs.getMetaData();
		TableModel model = new AbstractTableModel() {

			private static final long serialVersionUID = 1L;

			public int getRowCount() {
				try {
					rs.last();
					return rs.getRow();
				} catch (SQLException e) {
					e.printStackTrace();
					return 0;
				}
			}

			public int getColumnCount() {
				try {
					return rsmd.getColumnCount();
				} catch (SQLException e) {
					e.printStackTrace();
					return 0;
				}
			}

			public Object getValueAt(int rowIndex, int columnIndex) {
				try {
					rs.absolute(rowIndex + 1);
					return rs.getObject(columnIndex + 1);
				} catch (SQLException e) {
					e.printStackTrace();
					return null;
				}
			}

			@Override
			public String getColumnName(int column) {
				try {
					return rsmd.getColumnName(column + 1);
				} catch (SQLException ex) {
					ex.printStackTrace();
					return super.getColumnName(column + 1);
				}
			}
		};
		return model;
	}

	/**
	 * JOptionPane 显示正常的简单信息框<br>
	 * 该弹出框将出现在屏幕的中央,标题为消息
	 * 
	 * @param message
	 *            显示的信息,可以是组件,如JPanel
	 */
	public static void showSimpleNormalInfo(Object message) {
		JOptionPane.showMessageDialog(null, message);
	}

	/**
	 * JOptionPane 显示正常信息
	 * 
	 * @param parent
	 *            父组件,可以为NULL
	 * @param message
	 *            显示的信息,可以是组件,如JPanel
	 * @param title
	 *            标题 可以为NULL
	 */
	public static void showNormalInfo(Component parent, Object message,
			String title) {
		JOptionPane.showMessageDialog(parent, message, title,
				JOptionPane.PLAIN_MESSAGE);
	}

	/**
	 * JOptionPane 显示详细信息<br>
	 * 常用于在JTable等组件中显示一行的详细信息<br>
	 * 优势:使用此方法显示的信息可以复制
	 * 
	 * @param parent
	 *            父组件 可以为NULL
	 * @param title
	 *            标题 若为NULL则标题是 "详细信息"
	 * @param message
	 *            显示的信息,可以使用\n分隔为多行
	 * @param r
	 *            显示信息的区域的行数 默认为5行
	 * @param c
	 *            显示信息的区域的列数 默认为40列
	 */
	public static void showDetailInfo(Component parent, String title,
			StringBuilder message, int r, int c) {
		JTextArea area = new JTextArea(message.toString(), 5, 40);
		if (r > 0 && r != 5) {
			area.setRows(r);
		}
		if (c > 0 && c != 40) {
			area.setColumns(c);
		}
		area.setEditable(false);
		if (title == null) {
			title = "详细信息";
		}
		showNormalInfo(parent, new JScrollPane(area), title);
	}

	/**
	 * JOptionPane 显示异常或错误信息
	 * 
	 * @param parent
	 *            父组件,可以为NULL
	 * @param title
	 *            标题,可以为NULL
	 * @param message
	 *            显示的信息,可以是组件,如JPanel
	 */
	public static void showErrorInfo(Component parent, String title,
			Object message) {
		JOptionPane.showMessageDialog(parent, message, title,
				JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * JOptionPane 显示确认信息
	 * 
	 * @param parent
	 *            父组件,可以为NULL
	 * @param title
	 *            标题,可以为NULL
	 * @param message
	 *            显示的信息,可以是组件,如JPanel
	 * @return JOptionPane.OK_OPTION or not
	 */
	public static int showConfirmInfo(Component parent, String title,
			Object message) {
		int i = JOptionPane.showConfirmDialog(parent, message, title,
				JOptionPane.OK_CANCEL_OPTION);
		return i;
	}

}
